home *** CD-ROM | disk | FTP | other *** search
- /* -----------------------------------------------------------------------------
-
- GoldED API client example code, ©1995 Dietmar Eilert. Dice:
-
- dcc main.c -// -proto -mi -r -2.0 -l reqtoolss.lib -o ram:spell
-
- Note: Compiling this code requires reqtools includes & reqtools linker
- libraries. The ReqTools library is © Nico François.
-
- The following code adds spell checking capabilities to GoldED. It is based on
- the ISpell package and the ISpell dictionary (available on Fish disks). ISpell
- has to be installed properly (within a valid command path) before you can use
- this API client. This example uses synchronous ARexx communication: Requests
- are PutMsg()'ed to GoldED's port, followed by a WaitPort() to get the editor's
- response. This works fine since we need no ARexx communication after the API
- link has been established. If there were ARexx communication with GoldED AFTER
- the link has been established (i.e. after sending the 'API PORT=...' command to
- register with GoldED), we would have to use an asynchronous design beeing
- capable of answering incoming API messages while waiting for completion of
- ARexx requests sent to GoldED.
-
- -------------------------------------------------------------------------------
- */
-
- /// "includes"
-
- #define Prototype extern
-
- #include <exec/exec.h>
- #include <string.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <dos/dos.h>
- #include <dos/dostags.h>
- #include <dos/rdargs.h>
- #include <intuition/intuition.h>
- #include <utility/tagitem.h>
- #include <libraries/gadtools.h>
- #include <rexx/errors.h>
- #include <rexx/rxslib.h>
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
- #include <clib/graphics_protos.h>
- #include <clib/intuition_protos.h>
- #include <clib/diskfont_protos.h>
- #include <clib/rexxsyslib_protos.h>
- #include <clib/gadtools_protos.h>
- #include <clib/reqtools_protos.h>
- #include <clib/alib_protos.h>
- #include <devices/audio.h>
- #include "golded:api/include/golded.h"
-
- Prototype void main(int, char **);
- Prototype BOOL InitISpell(void);
- Prototype void HandleAPI(BOOL, BOOL, char *);
- Prototype ULONG *SendRexxCommand(char *, char *, struct MsgPort *, char *);
- Prototype void CheckWord(struct APIMessage *, struct MsgPort *, BOOL, BOOL);
- Prototype void Beep(void);
- Prototype UWORD ComputeX(struct TextFont *, UWORD);
- Prototype UWORD ComputeY(struct TextFont *, UWORD);
- Prototype char *ShowSpell(char *, struct List *);
- Prototype struct Node *SearchNode(struct List *, UWORD);
-
- struct Library *ReqToolsBase;
-
- ///
- /// "main"
-
- void
- main(int argc, char **argv)
- {
- const char *version = "$VER: spell 1.5 (" __COMMODORE_DATE__ ")";
-
- struct RDArgs *rdArgs;
-
- ULONG args[] = { 0, 0, 0 };
-
- if (rdArgs = ReadArgs("ASK/S,NOFLASH/S,HOST/K/A", args, NULL)) {
-
- if (ReqToolsBase = (struct ReqToolsBase *)OpenLibrary("reqtools.library", 0)) {
-
- if (InitISpell())
- HandleAPI(args[0], args[1], (char *)args[2]);
-
- CloseLibrary(ReqToolsBase);
- }
-
- FreeArgs(rdArgs);
- }
- else
- puts("syntax error: SPELL ASK/S,HOST/K/A");
-
- exit(0);
- }
-
- ///
- /// "init"
-
- /* -------------------------------- IntiISpell ---------------------------------
-
- Prepare ISpell. Return TRUE if successful.
-
- */
-
- BOOL
- InitISpell()
- {
- if (FindPort("IRexxSpell"))
-
- return(TRUE);
-
- else {
-
- struct TagItem tags[] = {SYS_Output, NULL, SYS_Input, NULL, SYS_Asynch, TRUE, TAG_DONE};
-
- if (SystemTagList("ispell -r", tags) != -1) {
-
- UWORD n;
-
- for (n = 0; n < 100; n++, Delay(10))
- if (FindPort("IRexxSpell"))
- return(TRUE);
- }
- }
-
- puts("ISpell not available");
-
- return(FALSE);
- }
-
- ///
- /// "api management"
-
- /* --------------------------------- HandleAPI ---------------------------------
-
- Register with GoldED & handle incoming API messages.
-
- */
-
- void
- HandleAPI(ask, noFlash, host)
-
- BOOL ask, noFlash;
- char *host;
- {
- struct MsgPort *rexxPort, *apiPort;
-
- if (apiPort = CreateMsgPort()) {
-
- if (rexxPort = CreateMsgPort()) {
-
- char command[255];
- ULONG *result;
-
- sprintf(command, "API PORT=%ld CLASS=%ld", apiPort, API_CLASS_ROOT | API_CLASS_KEY);
-
- if (result = SendRexxCommand(host, command, rexxPort, NULL)) {
-
- if (*result == RC_OK) {
-
- BOOL active = TRUE;
-
- do {
-
- struct APIMessage *apiMsg, *nextMsg;
-
- while (!(apiMsg = (struct APIMessage *)GetMsg(apiPort)))
- WaitPort(apiPort);
-
- do {
-
- for (nextMsg = apiMsg; nextMsg; nextMsg = nextMsg->api_Next) {
-
- if (nextMsg->api_State == API_STATE_NOTIFY) {
-
- switch (nextMsg->api_Class) {
-
- case API_CLASS_ROOT:
-
- switch (nextMsg->api_Action) {
-
- case API_ACTION_DIE:
-
- active = FALSE;
- break;
-
- case API_ACTION_INTRODUCE:
-
- static struct TagItem tags[] = {
-
- API_Client_Name, "spell",
- API_Client_Copyright, "©1995 Dietmar Eilert",
- API_Client_Purpose, "Adds online spell checking",
- TAG_DONE
- };
-
- nextMsg->api_Data = tags;
- break;
-
- default:
-
- nextMsg->api_Error = API_ERROR_UNKNOWN;
- }
-
- break;
-
- case API_CLASS_KEY:
-
- switch (nextMsg->api_Action) {
-
- case API_ACTION_VANILLAKEY:
-
- // checks are performed after white space characters:
-
- if ((UBYTE)nextMsg->api_Data < 'A')
- CheckWord(nextMsg, rexxPort, ask, noFlash);
-
- break;
-
- default:
-
- nextMsg->api_Error = API_ERROR_UNKNOWN;
- }
- break;
-
- default:
-
- nextMsg->api_Error = API_ERROR_UNKNOWN;
- }
- }
- }
-
- ReplyMsg((struct Message *)apiMsg);
-
- } while (apiMsg = (struct APIMessage *)GetMsg(apiPort));
-
- } while (active);
- }
- }
-
- SendRexxCommand("IRexxSpell", "EXIT", rexxPort, NULL);
-
- DeleteMsgPort(rexxPort);
- }
-
- DeleteMsgPort(apiPort);
- }
- }
-
-
- ///
- /// "check word"
-
- /* --------------------------------- CheckWord ---------------------------------
-
- Check word. This function is called BEFORE GoldED actually inserts a white
- space character (space, colon, ...) at the current cursor position. We assume
- the current position to be a white space character to guarantee correct
- behavior if the user inserts a character into a word. If ISpell complains about
- a word we will either issue a beep (ask = FALSE) or additionally display a list
- of suggestions (<ask> = TRUE).
-
- Excerpt taken from man/ispell.1: If the word is not in the dictionary, but
- there are near misses, then the result line contains an '&', a space, and a
- list of the near misses separated by spaces.
-
- */
-
- void
- CheckWord(apiMsg, rexxPort, ask, noFlash)
-
- struct APIMessage *apiMsg;
- struct MsgPort *rexxPort;
- BOOL ask, noFlash;
- {
- static UBYTE buffer[4096];
-
- struct EditConfig *config;
- UBYTE *next;
- UWORD column;
-
- config = apiMsg->api_Config;
- column = config->Column;
-
- // create copy of current line
-
- movmem(config->CurrentBuffer, buffer, config->CurrentLen);
-
- // cursor placed directly after word ?
-
- if (column && (buffer[--column] > '@')) {
-
- static char word[1000], result[1000];
-
- UWORD wordLen;
-
- // find beginning of word
-
- for (next = buffer + column, wordLen = 1; column && (*(next - 1) > '@'); --column, --next)
- ++wordLen;
-
- // create ISpell command line
-
- movmem(next, word, wordLen);
-
- word[wordLen] = 0;
-
- strins(word, "QUICKCHECK ");
-
- // make ISpell check word
-
- if (SendRexxCommand("IRexxSpell", word, rexxPort, result)) {
-
- if (stricmp(result, "ok")) {
-
- if (noFlash)
- Beep();
- else
- DisplayBeep(NULL);
-
- // send additional CHECK command to get further information
-
- if (ask && SendRexxCommand("IRexxSpell", word + 5, rexxPort, result)) {
-
- if (*result == '&') {
-
- // translate ISpell result string (suggestions) into exec list
-
- struct List list;
- struct Node *node, *nextNode;
- char *start, *end, *selection;
-
- for (NewList(&list), end = result + 2; *end;) {
-
- for (start = end; *end && (*end != 32); ++end);
-
- if (node = (struct Node *)AllocVec(sizeof(struct Node), MEMF_ANY | MEMF_CLEAR)) {
-
- node->ln_Name = start;
- AddTail(&list, node);
- }
-
- if (*end)
- *end++ = 0;
- }
-
- // ask for user selection from list, insert user selection into text
-
- if (selection = ShowSpell(apiMsg->api_Global->F_ScrnName, &list)) {
-
- static struct APIModifyRequest modifyRequest;
-
- UWORD newLen = strlen(selection);
-
- if (newLen != wordLen)
- movmem(next + wordLen, next + newLen, config->CurrentLen - (next - buffer));
-
- movmem(selection, next, newLen);
-
- // make GoldED change the current line
-
- modifyRequest.mr_Next = NULL;
- modifyRequest.mr_Line = config->Line;
- modifyRequest.mr_Column = config->Column + (newLen - wordLen);
- modifyRequest.mr_Size = config->CurrentLen + (newLen - wordLen);
- modifyRequest.mr_Data = buffer;
-
- apiMsg->api_Modify = &modifyRequest;
- }
-
- // free list of suggestions
-
- for (node = list.lh_Head; nextNode = node->ln_Succ; node = nextNode)
- FreeVec(node);
- }
- }
- }
- }
- }
- }
-
- ///
- /// "gui"
-
- /* --------------------------------- ShowSpell ---------------------------------
-
- Show ISpell suggestions. Return user selection or NULL.
-
- */
-
- char *
- ShowSpell(screen, list)
-
- char *screen;
- struct List *list;
- {
- char *result = NULL;
-
- struct Screen *scr;
-
- if (scr = LockPubScreen(screen)) {
-
- struct TextFont *font;
-
- if (font = OpenDiskFont(scr->Font)) {
-
- APTR visualInfo;
-
- if (visualInfo = GetVisualInfoA(scr, NULL )) {
-
- struct Gadget *context, *glist, *gad;
-
- if (context = CreateContext(&glist)) {
-
- UWORD ww, wh, offX, offY;
- LONG displayWidth, displayHeight;
-
- struct Window *win;
-
- offX = scr->WBorLeft;
- offY = scr->RastPort.TxHeight + scr->WBorTop + 1;
-
- struct NewGadget newGad = {
-
- offX,
- offY,
- ComputeX(font, 221),
- ComputeY(font, 156),
- NULL, scr->Font, 0, 0, visualInfo, 0
- };
-
- gad = CreateGadget(LISTVIEW_KIND, context, &newGad, GTLV_ShowSelected, NULL, GTLV_Labels, list, GTLV_Selected, 0, TAG_DONE);
-
- rtGetVScreenSize(scr, &displayWidth, &displayHeight);
-
- ww = ComputeX(font, 221);
- wh = ComputeY(font, 156);
-
- if (win = OpenWindowTags( NULL,
-
- WA_Left, ((displayWidth - ww)>>1) - scr->ViewPort.DxOffset,
- WA_Top, ((displayHeight - wh)>>1) - scr->ViewPort.DyOffset,
- WA_Width, ww + offX + scr->WBorRight,
- WA_Height, wh + offY + scr->WBorBottom,
- WA_IDCMP, LISTVIEWIDCMP | IDCMP_CLOSEWINDOW | IDCMP_VANILLAKEY | IDCMP_RAWKEY,
- WA_Flags, WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET | WFLG_SMART_REFRESH | WFLG_ACTIVATE,
- WA_Gadgets, glist,
- WA_Title, "ISpell",
- WA_PubScreen, scr,
- TAG_DONE
-
- )) {
-
- ULONG class;
- UWORD active;
-
- active = 0;
- result = list->lh_Head->ln_Name;
-
- struct IntuiMessage *msg;
- struct Node *node;
-
- GT_RefreshWindow(win, NULL);
-
-
- do {
-
- while (!(msg = GT_GetIMsg(win->UserPort)))
- WaitPort(win->UserPort);
-
- switch (class = msg->Class) {
-
- case RAWKEY:
-
- WORD step = (msg->Code == CURSORUP) ? -1 : 1;
-
- if (node = SearchNode(list, active + step)) {
-
- active += step;
- result = node->ln_Name;
-
- GT_SetGadgetAttrs(gad, win, NULL, GTLV_Selected, active, GTLV_MakeVisible, active, TAG_DONE);
- }
-
- break;
-
- case IDCMP_VANILLAKEY:
-
- if (msg->Code == 27)
- class = CLOSEWINDOW;
-
- if (msg->Code == 13)
- class = IDCMP_GADGETUP;
-
- break;
-
- case IDCMP_GADGETUP:
-
- result = SearchNode(list, active = msg->Code)->ln_Name;
- break;
- }
-
- GT_ReplyIMsg(msg);
-
- } while ((class & (GADGETUP | CLOSEWINDOW)) == NULL);
-
- if (class == CLOSEWINDOW)
- result = NULL;
-
- CloseWindow(win);
- }
- }
- FreeVisualInfo(visualInfo);
- }
- }
- UnlockPubScreen(screen, scr);
- }
-
- return(result);
- }
-
- /* --------------------------------- ComputeX ----------------------------------
-
- Resize element of width <value> according to current font
-
- */
-
- UWORD
- ComputeX(font, value)
-
- UWORD value;
- struct TextFont *font;
- {
- return((font->tf_XSize * value) / 8);
- }
-
- /* --------------------------------- ComputeY ----------------------------------
-
- Resize element of height <value> according to current font
-
- */
-
- UWORD
- ComputeY(font, value)
-
- UWORD value;
- struct TextFont *font;
- {
- return((font->tf_YSize * value) / 8);
- }
-
- ///
- /// "misc"
-
- /* ---------------------------------- SearchNode --------------------------------
-
- Return pointer to node if ordinal number (0, ...) is known.
-
- */
-
- struct Node *
- SearchNode(list, ordinal)
-
- struct List *list;
- UWORD ordinal;
- {
- struct Node *node;
-
- for (node = list->lh_Head; node->ln_Succ; --ordinal, node = node->ln_Succ)
- if (!ordinal)
- return(node);
-
- return(NULL);
- }
-
- /* ----------------------------------- Beep ------------------------------------
-
- Short audible beep
-
- */
-
- void
- Beep()
- {
- struct IOAudio *audioIO;
-
- if (audioIO = (struct IOAudio *)AllocVec(sizeof(struct IOAudio), MEMF_PUBLIC | MEMF_CLEAR)) {
-
- struct MsgPort *audioMP;
-
- if (audioMP = CreateMsgPort()) {
-
- UBYTE whichannel[] = { 1, 2, 4, 8 };
-
- audioIO->ioa_Request.io_Message.mn_ReplyPort = audioMP;
- audioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
- audioIO->ioa_Request.io_Command = ADCMD_ALLOCATE;
- audioIO->ioa_Request.io_Flags = ADIOF_NOWAIT;
- audioIO->ioa_AllocKey = 0;
- audioIO->ioa_Data = whichannel;
- audioIO->ioa_Length = sizeof(whichannel);
-
- if (!OpenDevice("audio.device", 0, (struct IORequest *)audioIO, 0)) {
-
- __chip const static UBYTE waveptr[2] = {127, -127};
-
- audioIO->ioa_Request.io_Message.mn_ReplyPort = audioMP;
- audioIO->ioa_Request.io_Command = CMD_WRITE;
- audioIO->ioa_Request.io_Flags = ADIOF_PERVOL;
-
- audioIO->ioa_Data = waveptr;
- audioIO->ioa_Length = 2;
- audioIO->ioa_Period = 1015;
- audioIO->ioa_Volume = 32;
- audioIO->ioa_Cycles = 60; // 44;
-
- BeginIO((struct IORequest *)audioIO );
-
- WaitPort(audioMP);
- GetMsg (audioMP);
-
- CloseDevice((struct IORequest *)audioIO);
- }
-
- DeleteMsgPort(audioMP);
- }
-
- FreeVec(audioIO);
- }
- }
-
- ///
- /// "arexx"
-
- /* ---------------------------------- SendRexxCommand -------------------------
-
- Send ARexx message & wait for answer. Return pointer to result or NULL.
-
- */
-
- ULONG *
- SendRexxCommand(port, cmd, replyPort, buffer)
-
- char *cmd, *port, *buffer;
- struct MsgPort *replyPort;
- {
- struct MsgPort *rexxport;
-
- Forbid();
-
- if (rexxport = FindPort(port)) {
-
- struct RexxMsg *rexxMsg, *answer;
-
- if (rexxMsg = CreateRexxMsg(replyPort, NULL, NULL)) {
-
- if (rexxMsg->rm_Args[0] = CreateArgstring(cmd, strlen(cmd))) {
-
- static ULONG result;
-
- rexxMsg->rm_Action = RXCOMM | RXFF_RESULT;
-
- PutMsg(rexxport, &rexxMsg->rm_Node);
-
- do {
-
- WaitPort(replyPort);
-
- if (answer = (struct RexxMsg *)GetMsg(replyPort))
- result = answer->rm_Result1;
-
- } while (!answer);
-
- Permit();
-
- if (answer->rm_Result1 == RC_OK) {
-
- if (answer->rm_Result2) {
-
- if (buffer)
- strcpy(buffer, (char *)answer->rm_Result2);
-
- DeleteArgstring((char *)answer->rm_Result2);
- }
- }
-
- DeleteArgstring((char *)ARG0(answer));
-
- DeleteRexxMsg(answer);
-
- return(&result);
- }
- }
- }
-
- Permit();
-
- return(NULL);
- }
-
- ///
-